<?php
/**
 * Description:
 * Author: hezhizheng
 * Date: 2018/11/16
 * Time: 9:06
 * Created by Created by Panxsoft.
 */

namespace App\Services\EasySms;

use App\Exceptions\ApiErrCode;
use App\Exceptions\ApiException;
use App\Models\Setting;
use App\Services\Locale\Language;
use App\Services\MobileApp\AppEnv;
use Illuminate\Support\Str;
use Overtrue\EasySms\EasySms;
use Overtrue\EasySms\Exceptions\InvalidArgumentException;
use Overtrue\EasySms\Exceptions\NoGatewayAvailableException;

/**
 * @link https://github.com/overtrue/easy-sms
 * Class EasySmsService
 * @package App\Services\EasySms
 */
class EasySmsService
{
    // 中国的国家区号
    const COUNTRY_CODE_CN = 86;

    const PKX_ALI_SMS_CN_HOST = 'pkx.ali.sms.cn_host';
    const PROXY_URL_PATH = 'api/v1/app/common/sms-proxy';

    private static $sms_sign;

    public static function config()
    {
        $config = [
            // HTTP 请求的超时时间（秒）
            'timeout'  => 5.0,

            // 默认发送配置
            'default'  => [
                // 网关调用策略，默认：顺序调用
                'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class,

                // 默认可用的发送网关
                'gateways' => [
                    'aliyun',
                ],
            ],
            // 可用的网关配置
            'gateways' => [
                'errorlog' => [
                    'file' => storage_path('logs/easy-sms.log'),
                ],
                'aliyun'   => [
                    'access_key_id'     => config('pkx.ali.sms.access_key_id'),
                    'access_key_secret' => config('pkx.ali.sms.access_key_secret'),
                    'sign_name'         => self::$sms_sign,
                ],
            ],
        ];

        return $config;
    }

    /**
     * @param $phone
     * @param $verify_code
     * @param $dial_code
     * @return array
     * @throws \Exception
     */
    public function registerSend($phone, $verify_code, $dial_code)
    {
        try {
            $send = $this->sendLocaleRegisterMessage($phone, $verify_code, $dial_code);
        } catch (NoGatewayAvailableException  $exception) {
            $exception = $exception->getException('aliyun');

            logger($exception);

            throw new ApiException(ApiErrCode::SMS_SEND_FAILED, trans('service.sms_failed_to_send', [
                'tip' => $exception->getMessage()
            ]));
        }

        return $send;
    }

    /**
     * @param $phone
     * @param $verify_code
     *
     * @param $dial_code
     *
     * @return array
     * @throws ApiException
     * @throws \Exception
     */
    public function resetPwdSend($phone, $verify_code, $dial_code)
    {
        try {
            $send = $this->sendLocaleResetPasswordMessage($phone, $verify_code, $dial_code);
        } catch (NoGatewayAvailableException $exception) {
            $gate_way_exception = $exception->getException('aliyun');
            throw new ApiException(ApiErrCode::SMS_SEND_FAILED, trans('service.sms_failed_to_send', [
                'tip' => $gate_way_exception->getMessage()
            ]));
        }

        return $send;
    }

    /**
     * @param $phone
     * @param $password
     * @param $dial_code
     * @return array
     * @throws ApiException
     * @throws \Exception
     */
    public function sendNewPassword($phone, $password, $dial_code)
    {
        try {
            $send = $this->sendLocaleNewPasswordMessage($phone, $password, $dial_code);
        } catch (NoGatewayAvailableException  $exception) {
            logger($exception->getException('aliyun'));
            throw new ApiException(ApiErrCode::SMS_SEND_FAILED, trans('service.sms_failed_to_send', [
                'tip' => $exception->getMessage()
            ]));
        }

        return $send;
    }

    /**
     * @param $phone
     * @param $verify_code
     *
     * @param $dial_code
     * @return array
     * @throws \Exception
     */
    public function sendLocaleRegisterMessage($phone, $verify_code, $dial_code): array
    {
        if ($dial_code === self::COUNTRY_CODE_CN) {  // 只能发国内的手机号
            $message = [
                'template' => config('pkx.ali.sms.register_verify_tpl_code'),
                'data'     => [
                    // 这里的变量名称为阿里云上定义的变量
                    'code'    => $verify_code,
                ],
            ];

            $send = $this->sendByProxy(config('pkx.ali.sms.register_sign'), $phone, $message);
        } else {  // 只能发国际手机号（不能发国内的）
            self::$sms_sign = config('pkx.ali.sms.register_sign_en');
            $send = (new EasySms(self::config()))->send($dial_code.$phone, [
                'template' => config('pkx.ali.sms.register_verify_tpl_code_en'),
                'data'     => [
                    'code'    => $verify_code,
                ],
            ]);
        }

        return $send;
    }

    /**
     * @param $phone
     * @param $verify_code
     *
     * @param $dial_code
     * @return array
     * @throws \Exception
     */
    public function sendLocaleResetPasswordMessage($phone, $verify_code, $dial_code): array
    {
        if ($dial_code === self::COUNTRY_CODE_CN) {
            $message = [
                'template' => config('pkx.ali.sms.change_verify_tpl_code'),
                'data'     => [
                    'code'    => $verify_code,
                ],
            ];

            $send = $this->sendByProxy(config('pkx.ali.sms.change_verify_sign'), $phone, $message);
        } else {
            self::$sms_sign = config('pkx.ali.sms.change_verify_sign_en');
            $send = (new EasySms(self::config()))->send($dial_code.$phone, [
                'template' => config('pkx.ali.sms.change_verify_tpl_code_en'),
                'data'     => [
                    'code'    => $verify_code,
                ],
            ]);
        }

        return $send;
    }

    /**
     * @param $phone
     * @param $password
     *
     * @param $dial_code
     *
     * @return array
     * @throws \Exception
     */
    public function sendLocaleNewPasswordMessage($phone, $password, $dial_code): array
    {
        if ((int) $dial_code === self::COUNTRY_CODE_CN) {
            $message = [
                'template' => config('pkx.ali.sms.reset_pwd_verify_tpl_code'),
                'data'     => [
                    'password' => $password,
                ],
            ];

            $send = $this->sendByProxy(config('pkx.ali.sms.change_verify_sign'), $phone, $message);
        } else {
            self::$sms_sign = config('pkx.ali.sms.change_verify_sign_en');
            $send = (new EasySms(self::config()))->send($dial_code.$phone, [
                'template' => config('pkx.ali.sms.reset_pwd_verify_tpl_code_en'),
                'data'     => [
                    'password' => $password,
                ],
            ]);
        }

        return $send;
    }

    /**
     * 代理发送短信
     *
     * @param string $sign
     * @param string $to
     * @param array $message
     *
     * @return array
     * @throws \Exception
     */
    public function sendByProxy(string $sign, string $to, array $message)
    {
        if (config(self::PKX_ALI_SMS_CN_HOST)) {
            return $this->sendByChinaServer($sign, $to, $message);
        } else {
            return $this->send($sign, $to, $message);
        }
    }
    /**
     * 代理发送短信
     *
     * @param string $sign
     * @param string $to
     * @param array $message
     *
     * @return array
     * @throws \Exception
     */
    public function send(string $sign, string $to, array $message)
    {
        self::$sms_sign = $sign;

        return (new EasySms(self::config()))->send($to, $message);
    }

    /**
     * aliyun 禁止国外 IP 发送国内短信，需要代理给国内服务器发
     *
     * @param string $sign
     * @param string $to
     * @param array $message
     *
     * @return mixed
     * @throws ApiException
     * @throws \App\Exceptions\ApiSilentException
     */
    public function sendByChinaServer(string $sign, string $to, array $message): array
    {
        $proxy_host = Str::finish(config(self::PKX_ALI_SMS_CN_HOST), '/')  ;

        $api = $proxy_host . self::PROXY_URL_PATH;

        $query = http_build_query([
            'sign'    => $sign,
            'to'      => $to,
            'message' => json_encode($message),
        ]);

        $res = file_get_contents("$api?$query");

        $res_json = json_decode($res, true);
        if (json_last_error()) {
            $msg = json_last_error_msg();
            throw new ApiException(ApiErrCode::SMS_PROXY_SEND_FAILED, "Proxy Server Error[$msg]");
        }

        if (! empty($res_json['code'])) {
            throw new ApiException(
                ApiErrCode::SMS_PROXY_SEND_FAILED, $res_json['error'] ?? 'Proxy SMS Unknown Error');
        }

        return $res_json;
    }
}